//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package tasks

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	bg_runner_core "atomgit.com/openlinksaas/api-server/bg_runner/core"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/alarm_dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_alarm_api"
	"go.mongodb.org/mongo-driver/mongo"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
)

//检查整个项目工单重新打开次数的告警，在调整告警配置后触发

type ProjectIssueReOpenCheck struct {
	ProjectId string `json:"projectId"`
}

func (t *ProjectIssueReOpenCheck) TaskType() string {
	return "ProjectIssueReOpenCheck"
}

func (t *ProjectIssueReOpenCheck) Execute(logger *zap.Logger) error {
	defer api_common.SendNoticeToProjectScope(context.Background(), t.ProjectId, &notices_project.UpdateAlarmStatNotice{
		ProjectId: t.ProjectId,
	})

	configItem, err := alarm_dao.ConfigDao.Get(context.Background(), t.ProjectId)
	if err != nil {
		return t.removeAlarm(context.Background())
	}
	if !configItem.EnableIssueReOpenCheck {
		return t.removeAlarm(context.Background())
	}
	issueItemList, err := issue_dao.IssueDao.ListByReOpen(context.Background(), t.ProjectId)
	if err != nil {
		return err
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return err
	}
	defer dao.EndSession(dbSess)

	_, err = dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = t.removeAlarm(sessCtx)
		if err != nil {
			return nil, err
		}
		for _, issueItem := range issueItemList {
			if issueItem.ReOpenCount >= configItem.IssueReOpenAlertValue {
				err = t.addAlarm(sessCtx, issueItem, project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_ALERT)
				if err != nil {
					return nil, err
				}
			} else if issueItem.ReOpenCount >= configItem.IssueReOpenHitValue {
				err = t.addAlarm(sessCtx, issueItem, project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT)
				if err != nil {
					return nil, err
				}
			}
		}
		return nil, nil
	})
	return err
}

func (t *ProjectIssueReOpenCheck) addAlarm(ctx context.Context, issueItem *issue_dao.IssueInfoDbItem, alarmType project_alarm_api.ALARM_TYPE) error {
	alarmId := fmt.Sprintf("%s:%d", issueItem.IssueId, uint32(alarmType))
	nowTime := time.Now().UnixNano() / 1e6
	alarmLevel := uint32(alarm_dao.ALARM_LEVEL_ALERT)
	if alarmType == project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT {
		alarmLevel = uint32(alarm_dao.ALARM_LEVEL_HIT)
	}
	alarm := &project_alarm_api.Alarm{
		AlarmId:   alarmId,
		ProjectId: t.ProjectId,
		TimeStamp: nowTime,
		AlarmType: alarmType,
		Title:     "",
	}
	if alarmType == project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT {
		alarm.Content = &project_alarm_api.Alarm_IssueReOpenHitInfo{
			IssueReOpenHitInfo: &project_alarm_api.IssueReOpenHitInfo{
				IssueId:   issueItem.IssueId,
				IssueType: uint32(issueItem.IssueType),
			},
		}
	} else if alarmType == project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_ALERT {
		alarm.Content = &project_alarm_api.Alarm_IssueReOpenAlertInfo{
			IssueReOpenAlertInfo: &project_alarm_api.IssueReOpenAlertInfo{
				IssueId:   issueItem.IssueId,
				IssueType: uint32(issueItem.IssueType),
			},
		}
	}

	content, err := proto.Marshal(alarm)
	if err != nil {
		return err
	}
	return alarm_dao.AlarmDao.Insert(ctx, &alarm_dao.AlarmDbItem{
		AlarmId:    alarmId,
		ProjectId:  t.ProjectId,
		TimeStamp:  nowTime,
		AlarmType:  uint32(alarmType),
		AlarmLevel: alarmLevel,
		Content:    content,
	})
}

func (t *ProjectIssueReOpenCheck) removeAlarm(ctx context.Context) error {
	err := alarm_dao.AlarmDao.RemoveByProject(ctx, t.ProjectId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_HIT))
	if err != nil {
		return err
	}
	return alarm_dao.AlarmDao.RemoveByProject(ctx, t.ProjectId, uint32(project_alarm_api.ALARM_TYPE_ALARM_TYPE_ISSUE_REOPEN_ALERT))
}

func (t *ProjectIssueReOpenCheck) NewInstance(jsonData []byte) (bg_runner_core.BackGroundTask, error) {
	obj := &ProjectIssueReOpenCheck{}
	err := json.Unmarshal(jsonData, obj)
	if err != nil {
		return nil, err
	}
	return obj, nil
}
